﻿#region << 文件说明 >>

/*----------------------------------------------------------------
 * 命名空间：Vampirewal.Core.FlowEngine.Model
 * 唯一标识：81628203-d750-4333-bf05-1da8a874e3ae
 * 文件名：VampirewalWorkFlowEngineServer
 *
 * 创建者：杨程
 * 电子邮箱：235160615@qq.com
 * 创建时间：2023/10/13 16:43:56
 * 版本：V1.0.0
 * 描述：
 *
 * ----------------------------------------------------------------
 * 修改人：
 * 时间：
 * 修改说明：
 *
 * 版本：V1.0.1
 *----------------------------------------------------------------*/

#endregion << 文件说明 >>

using System.Data;
using System.Drawing;
using Vampirewal.Core.Models.FlowEngine;

namespace Vampirewal.Core.FlowEngine;

/// <summary>
/// 流程引擎服务端服务
/// </summary>
public class VampirewalWorkFlowEngineServer : IVampirewalWorkFlowEngineServer
{
    /// <summary>
    /// 构造函数
    /// </summary>
    public VampirewalWorkFlowEngineServer()
    {
    }

    /// <inheritdoc/>
    public virtual async Task<string> StartWork(int FlowType, WorkParamCollection Params)
    {
        var option = VampirewalCoreContext.GetInstance().GetService<IVampirewalWorkFlowEngineOptionForServer>();

        var flow = option.GetFlowByType(FlowType);

        var repWork = VampirewalCoreContext.GetInstance().GetService<SqlSugarRepository<FlowWorkInfo>>();

        FlowWorkInfo work = new FlowWorkInfo()
        {
            FlowId = flow.BillId,
            Description = flow.Units.FirstOrDefault(f => f.IsFirst)?.Description,
            State = WorkStateType.Running,
            StartTime = DateTime.Now,
            WorkId = Guid.NewGuid().ToString(),
            Startor = Params["UserId"]
        };

        FlowTask CommitTask = new FlowTask()
        {
            WorkId = work.WorkId,
            ExcutorId = Params["UserId"],
            Excutor = Params["UserName"],
            NotifyTime = DateTime.Now,
            FinishTime = DateTime.Now,
            FlowUnitId = flow.Units.First(f => f.IsFirst).DtlId,
            State = WorkStateType.Finished,
            TaskId = Guid.NewGuid().ToString(),
        };

        FlowUserDisp disp = new FlowUserDisp()
        {
            DispId = Guid.NewGuid().ToString(),
            TaskId = CommitTask.TaskId,
            FinishTime = DateTime.Now,
            NotifyTime = DateTime.Now,
            IsPass = true,
            Opinion = "提交",
            State = WorkStateType.Finished,
            UserId = Params["UserId"],
        };

        try
        {
            repWork.CurrentBeginTran();

            await repWork.InsertAsync(work);

            await repWork.Change<FlowTask>().InsertAsync(CommitTask);

            await repWork.Change<FlowUserDisp>().InsertAsync(disp);

            repWork.CurrentCommitTran();

            await TaskRun(work.WorkId, true, "提交", Params);

            return work.WorkId;
        }
        catch (Exception ex)
        {
            repWork.CurrentRollbackTran();
            return "";
        }
    }

    /// <inheritdoc/>
    public async Task TaskRun(string WorkId, bool IsPass, string Opinion, WorkParamCollection Params)
    {
        var option = VampirewalCoreContext.GetInstance().GetService<IVampirewalWorkFlowEngineOptionForServer>();

        var repWork = VampirewalCoreContext.GetInstance().GetService<SqlSugarRepository<FlowWorkInfo>>();
        var work = await repWork.FirstOrDefaultAsync(f => f.State == WorkStateType.Running && f.WorkId == WorkId);

        if (work == null)
        {
            throw new Exception("该流程已结束！");
        }

        var TaskList = await repWork.Change<FlowTask>().ToListAsync(t => t.WorkId == work.WorkId, o => o.NotifyTime);

        var flow = option.GetFlowById(work.FlowId);

        var LaseTask = TaskList.Last();

        //获取当前任务的后续节点，因为节点连线可能多条
        var nextLinks = flow.Links.Where(w => w.PreviousUnitId == LaseTask.FlowUnitId).ToList();

        if (nextLinks.Count() > 1 && nextLinks.Any(a => string.IsNullOrEmpty(a.Condition)))
        {
            throw new Exception("存在多个下一级节点，但是有节点连线没有执行条件!");
        }
        else if (nextLinks.Count() > 1)
        {
            FlowLink SelectedLink = null;

            foreach (var link in nextLinks)
            {
                if (CheckCondition(link, flow, Params))
                {
                    SelectedLink = link;
                    break;
                }
            }

            if (SelectedLink == null)
            {
                throw new Exception("没有满足条件的分支！");
            }

            var ExcutionMode = VampirewalCoreContext.GetInstance().GetService<IVampirewalFlowUnitExcutionMode>();

            //根据满足条件的连线，获取到下一级节点
            var nextUnit = flow.Units.FirstOrDefault(f => f.DtlId == SelectedLink.NextUnitId);


            FlowTask nextTask = new FlowTask()
            {
                FlowUnitId= nextUnit.DtlId,
                State= WorkStateType.Running,
                NotifyTime= DateTime.Now,
                TaskId=Guid.NewGuid().ToString(),
                WorkId= WorkId,
            };

            //获取执行人
            var ExcutorUsers = nextUnit.ExcutionMode switch
            {
                ExcutionModeType.AssignUser => new List<Tuple<string, string>>() { new Tuple<string, string>(nextUnit.ExcutorId, nextUnit.ExcutorName) },
                ExcutionModeType.DepartmentHead => ExcutionMode.DepartmentHead(Params),
                ExcutionModeType.Role => ExcutionMode.Role(Params),
                ExcutionModeType.EveryOne => ExcutionMode.EveryOne(Params),
            };

            foreach (var item in ExcutorUsers)
            {
                FlowUserDisp disp = new FlowUserDisp()
                {
                    TaskId= nextTask.TaskId,
                    DispId=Guid.NewGuid().ToString(),
                    NotifyTime= nextTask.NotifyTime,
                    UserId=item.Item1,
                    UserName=item.Item2,
                    State= WorkStateType.Running,
                };

            }

            LaseTask.SetFinish();
        }
        else if (nextLinks.Count() == 1)
        {
        }
    }

    /// <inheritdoc/>
    public Task<bool> WorkIsComplate(string WorkId)
    {
        return Task.FromResult(true);
    }

    private object StringToOtherConver(Type targetType, string OldValue)
    {
        if (targetType == typeof(string))
            return OldValue;
        if (targetType == typeof(Int32))
            return Convert.ToInt32(OldValue);
        if (targetType == typeof(Int64))
            return Convert.ToInt64(OldValue);
        if (targetType == typeof(Double))
            return Convert.ToDouble(OldValue);
        if (targetType == typeof(Decimal))
            return Convert.ToDecimal(OldValue);
        if (targetType == typeof(DateTime))
            return Convert.ToDateTime(OldValue);

        return null;
    }

    /// <summary>
    /// 验证条件是否成立
    /// </summary>
    /// <param name="link"></param>
    /// <param name="flow"></param>
    /// <param name="Params"></param>
    /// <returns></returns>
    private bool CheckCondition(FlowLink link,Flow flow, WorkParamCollection Params )
    {
        var con = link.Condition.ToUpper();

        foreach (var param in Params)
        {
            var item = flow.Parameters.FirstOrDefault(f => f.ParameterName.ToUpper() == param.ParamName.ToUpper());

            //获取传递过来的参数值
            dynamic value = item.ValueType switch
            {
                ParameterValueType.Int => Convert.ToInt32(param.ParamValue),
                ParameterValueType.Decimal => Convert.ToDecimal(param.ParamValue),
                ParameterValueType.Double => Convert.ToDouble(param.ParamValue),
                ParameterValueType.DateTime => Convert.ToDateTime(param.ParamValue),
                ParameterValueType.Bool => Convert.ToBoolean(param.ParamValue),
                ParameterValueType.String => param.ParamValue.ToUpper()
            };

            con = con.Replace($"WORK.{param.ParamName.ToUpper()}", $"{value}");
        }

        //验证条件true或false
        DataTable dt = new DataTable();
        var result = (bool)dt.Compute(con, "");

        return result;
    }
}

/// <summary>
/// 临时使用的流程参数
/// </summary>
/// <typeparam name="T"></typeparam>
internal class CurFlowParam<T>
{
    /// <summary>
    /// 参数名称
    /// </summary>
    public string ParameterName { get; set; }

    /// <summary>
    /// 值
    /// </summary>
    public T Value { get; set; }
}

